package jp.co.iris_ltd.irisphotoeditor.widget;

import jp.co.iris_ltd.irisphotoeditor.IrisPhotoEditorApplication;
import jp.co.iris_ltd.irisphotoeditor.util.ArtTool;
import jp.co.iris_ltd.irisphotoeditor.util.HistoryStack;
import jp.co.iris_ltd.irisphotoeditor.util.PenArtTool;
import jp.co.iris_ltd.irisphotoeditor.util.StampArtTool;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class CanvasImageView extends ScaleImageView {
    private static final String TAG = "CanvasImageView";

    public static enum CanvaMode {
        Draw, Move,
    }

    public static enum ToolMode {
        None, Pen, Stamp, Text,
    }

    private Canvas mCanvas;
    private Bitmap mBitmap, mBaseBitmap;
    private boolean mTouchThrough = false;
    private HistoryStack<ArtTool> mHistoryStack;

    private ArtTool mCurrentArtTool;

    private CanvaMode mCanvasMode = CanvaMode.Draw;
    private ToolMode mToolMode = ToolMode.Pen;
    private Paint mPaint;
    private Paint mOutlinePaint;
    private Drawable mArtToolDrawable;

    public CanvasImageView(Context context) {
        super(context);
        init();
    }

    public CanvasImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CanvasImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
    }

    public void setup(Bitmap bitmap, boolean fixBitmap) {
        mHistoryStack = ((IrisPhotoEditorApplication) getContext()
                .getApplicationContext()).getHistory();
        mBitmap = bitmap;
        if (fixBitmap) {
            mBitmap = fixBitmapRotation(bitmap);
        }
        setImageBitmap(mBitmap);
        restoreCanvas();
    }

    private Bitmap fixBitmapRotation(Bitmap bitmap) {
        Bitmap result = bitmap;
        IrisPhotoEditorApplication appContext = (IrisPhotoEditorApplication) getContext()
                .getApplicationContext();
        int newOrientation = getResources().getConfiguration().orientation;
        int oldOrientation = appContext.getEditorOrientation();
        if (newOrientation != oldOrientation && oldOrientation != 0) {
            if (newOrientation == Configuration.ORIENTATION_LANDSCAPE) {
                Matrix matrix = new Matrix();
                matrix.setRotate(-90.0f);
                result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                        bitmap.getHeight(), matrix, false);
            } else if (newOrientation == Configuration.ORIENTATION_PORTRAIT) {
                Matrix matrix = new Matrix();
                matrix.setRotate(90.0f);
                result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                        bitmap.getHeight(), matrix, false);
            }
        }
        appContext.setEditorOrientation(newOrientation);
        return result;
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (mCurrentArtTool != null) {
            if (!mCurrentArtTool.isFinalized()) {
                canvas.save();
                float scale = getScale();
                canvas.scale(scale, scale);
            }
            mCurrentArtTool.drawCanvas(canvas);
            canvas.restore();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        boolean result;
        switch (mCanvasMode) {
        case Draw:
            result = this.onTouchEvent(event);
            break;
        case Move:
            result = super.onTouchEvent(event);
            break;
        default:
            result = false;
            break;
        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mCurrentArtTool != null) {
            int action = event.getAction();
            mCurrentArtTool.setPosition(event, getScale());
            if (action == MotionEvent.ACTION_UP) {
                mCurrentArtTool.setOffset(getTranslateX() * -1 / getScale(),
                        getTranslateY() * -1 / getScale());
                mCurrentArtTool.finalize();
                try {
                    final ArtTool tool = (ArtTool) mCurrentArtTool.clone();
                    mHistoryStack.add(tool);
                } catch (CloneNotSupportedException e) {
                    Log.e(TAG, "Failed to clone ArtTool");
                }

                mCurrentArtTool.drawCanvas(mCanvas);
                remakeArtTool();
                // mCurrentArtTool.onDrawingFinish();
            }
            invalidate();
        }
        return !mTouchThrough;
    }

    public void setCanvasMode(CanvaMode mode) {
        mCanvasMode = mode;
    }

    public CanvaMode getCanvasMode() {
        return mCanvasMode;
    }

    public void setArtTool(ArtTool artTool) {
        mCurrentArtTool = artTool;
        if (artTool instanceof PenArtTool) {
            mToolMode = ToolMode.Pen;
        } else if (artTool instanceof StampArtTool) {
            mToolMode = ToolMode.Stamp;
        }
    }

    public void setArtToolMode(ToolMode mode) {
        mToolMode = mode;
    }

    public ToolMode getToolMode() {
        return mToolMode;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mBitmap = bm;
        mBaseBitmap = bm.copy(Bitmap.Config.ARGB_8888, true);

        mCanvas = new Canvas(mBitmap);

        mCurrentArtTool = new PenArtTool();
        ((IrisPhotoEditorApplication) getContext().getApplicationContext())
                .setBitmap(mBitmap);
        ((IrisPhotoEditorApplication) getContext().getApplicationContext())
                .setBaseBitmap(mBaseBitmap);

    }

    public void setTouchThrough(boolean touchThrough) {
        mTouchThrough = touchThrough;
    }

    public boolean getTouchThrough() {
        return mTouchThrough;
    }

    public void restoreCanvas() {
        if (mHistoryStack != null) {
            setImageBitmap(mBaseBitmap.copy(Bitmap.Config.ARGB_8888, true));

            for (final ArtTool tool : mHistoryStack.iterateUndo()) {
                tool.drawCanvas(mCanvas);
            }
        }
    }

    public void undoCanvas() {
        mHistoryStack.undo();
        restoreCanvas();
        invalidate();
    }

    public void redoCanvas() {
        mHistoryStack.redo();
        restoreCanvas();
        invalidate();
    }

    public HistoryStack<ArtTool> resetHistory() {
        mHistoryStack = new HistoryStack<ArtTool>();
        return mHistoryStack;
    }

    public void setPaint(Paint paint) {
        mPaint = paint;
    }

    public void setPaint(Paint inlinePaint, Paint outlinePaint) {
        mPaint = inlinePaint;
        mOutlinePaint = outlinePaint;
    }

    public void setArtToolDrawable(Drawable d) {
        mArtToolDrawable = d;
    }

    public void remakeArtTool() {
        switch (mToolMode) {
        case Pen:
            if (mPaint != null && mOutlinePaint != null) {
                mCurrentArtTool = new PenArtTool(mPaint, mOutlinePaint);
            }
            break;
        case Stamp:
            if (mArtToolDrawable != null) {
                mCurrentArtTool = new StampArtTool(mArtToolDrawable);
            }
            break;
        default:
            break;
        }
    }
}
